﻿Imports System
Imports System.Collections.Generic
Imports System.Collections.Specialized
Imports System.Configuration
Imports System.Diagnostics
Imports System.Globalization
Imports System.Threading
Imports System.Transactions
Imports System.Workflow.Runtime

Namespace System.Workflow.Runtime.Hosting
    Public Class SharedConnectionWorkflowCommitWorkBatchService
        Inherits WorkflowCommitWorkBatchService
        ' Methods
        Public Sub New(ByVal parameters As NameValueCollection)
            Me.tableSyncObject = New Object
            If (parameters Is Nothing) Then
                Throw New ArgumentNullException("parameters", ExecutionStringManager.MissingParameters)
            End If
            If (parameters.Count > 0) Then
                Dim str As String
                For Each str In parameters.Keys
                    If (String.Compare("EnableRetries", str, StringComparison.OrdinalIgnoreCase) = 0) Then
                        Me._enableRetries = Boolean.Parse(parameters.Item(str))
                        Me._ignoreCommonEnableRetries = True
                    End If
                Next
            End If
            Me.configParameters = parameters
        End Sub

        Public Sub New(ByVal connectionString As String)
            Me.tableSyncObject = New Object
            If String.IsNullOrEmpty(connectionString) Then
                Throw New ArgumentNullException("connectionString", ExecutionStringManager.MissingConnectionString)
            End If
            Me.unvalidatedConnectionString = connectionString
        End Sub

        Private Sub AddToConnectionInfoTable(ByVal transaction As Transaction, ByVal connectionInfo As SharedConnectionInfo)
            SyncLock Me.tableSyncObject
                Me.transactionConnectionTable.Add(transaction, connectionInfo)
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, String.Concat(New Object() { "AddToConnectionInfoTable ", transaction.GetHashCode, " in table of count ", Me.transactionConnectionTable.Count }))
            End SyncLock
        End Sub

        Protected Friend Overrides Sub CommitWorkBatch(ByVal commitWorkBatchCallback As CommitWorkBatchCallback)
            Dim event2 As ManualResetEvent
            Dim retry As New DbRetry(Me._enableRetries)
            Dim maxRetries As Short = retry.MaxRetries
        Label_0013:
            event2 = New ManualResetEvent(False)
            Dim transaction As Transaction = Nothing
            Dim connectionInfo As SharedConnectionInfo = Nothing
            Try 
                If (Nothing Is Transaction.Current) Then
                    maxRetries = 0
                    transaction = New CommittableTransaction
                    connectionInfo = New SharedConnectionInfo(Me.dbResourceAllocator, transaction, False, event2)
                Else
                    transaction = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete)
                    connectionInfo = New SharedConnectionInfo(Me.dbResourceAllocator, transaction, True, event2)
                End If
                Me.AddToConnectionInfoTable(transaction, connectionInfo)
                [Using] scope As TransactionScope = New TransactionScope(transaction)
                    Try 
                        commitWorkBatchCallback.Invoke
                        scope.Complete
                    Finally
                        Me.RemoveConnectionFromInfoTable(transaction)
                        event2.Set
                    End Try
                End [Using]
                Dim transaction2 As CommittableTransaction = [TryCast](transaction,CommittableTransaction)
                If (Not transaction2 Is Nothing) Then
                    transaction2.Commit
                End If
                Dim transaction3 As DependentTransaction = [TryCast](transaction,DependentTransaction)
                If (Not transaction3 Is Nothing) Then
                    transaction3.Complete
                End If
            Catch exception As Exception
                transaction.Rollback
                WorkflowTrace.Host.TraceEvent(TraceEventType.Error, 0, ("SharedConnectionWorkflowCommitWorkBatchService caught exception from commitWorkBatchCallback: " & exception.ToString))
                If Not retry.TryDoRetry((maxRetries)) Then
                    Throw
                End If
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, ("SharedConnectionWorkflowCommitWorkBatchService retrying commitWorkBatchCallback (retry attempt " & maxRetries.ToString(CultureInfo.InvariantCulture) & ")"))
                goto Label_0013
            Finally
                event2.Close
                If (Not transaction Is Nothing) Then
                    transaction.Dispose
                End If
            End Try
        End Sub

        Friend Function GetConnectionInfo(ByVal transaction As Transaction) As SharedConnectionInfo
            Return Me.LookupConnectionInfoTable(transaction)
        End Function

        Private Function LookupConnectionInfoTable(ByVal transaction As Transaction) As SharedConnectionInfo
            SyncLock Me.tableSyncObject
                Return Me.transactionConnectionTable.Item(transaction)
            End SyncLock
        End Function

        Protected Overrides Sub OnStopped()
            WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService: Stopping")
            Dim pair As KeyValuePair([Of] Transaction, SharedConnectionInfo)
            For Each pair In Me.transactionConnectionTable
                pair.Value.Dispose
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, ("Removing transaction " & pair.Key.GetHashCode))
            Next
            Me.transactionConnectionTable.Clear
            Me.dbResourceAllocator = Nothing
            MyBase.OnStopped
        End Sub

        Private Sub RemoveConnectionFromInfoTable(ByVal transaction As Transaction)
            SyncLock Me.tableSyncObject
                Dim info As SharedConnectionInfo
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, ("TransactionCompleted " & transaction.GetHashCode))
                If Me.transactionConnectionTable.TryGetValue(transaction, info) Then
                    info.Dispose
                    Me.transactionConnectionTable.Remove(transaction)
                Else
                    WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, String.Concat(New Object() { "TransactionCompleted ", transaction.GetHashCode, " not found in table of count ", Me.transactionConnectionTable.Count }))
                End If
            End SyncLock
        End Sub

        Protected Friend Overrides Sub Start()
            WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService: Starting")
            Me.dbResourceAllocator = New DbResourceAllocator(MyBase.Runtime, Me.configParameters, Me.unvalidatedConnectionString)
            If (Me.transactionConnectionTable Is Nothing) Then
                Me.transactionConnectionTable = New Dictionary([Of] Transaction, SharedConnectionInfo)
            End If
            If (Not Me._ignoreCommonEnableRetries AndAlso (Not MyBase.Runtime Is Nothing)) Then
                Dim commonParameters As NameValueConfigurationCollection = MyBase.Runtime.CommonParameters
                If (Not commonParameters Is Nothing) Then
                    Dim str As String
                    For Each str In commonParameters.AllKeys
                        If (String.Compare("EnableRetries", str, StringComparison.OrdinalIgnoreCase) = 0) Then
                            Me._enableRetries = Boolean.Parse(commonParameters.Item(str).Value)
                            Exit For
                        End If
                    Next
                End If
            End If
            MyBase.Start
        End Sub


        ' Properties
        Friend ReadOnly Property ConnectionString As String
            Get
                If (Me.dbResourceAllocator Is Nothing) Then
                    If (MyBase.Runtime Is Nothing) Then
                        Throw New InvalidOperationException(ExecutionStringManager.WorkflowRuntimeNotStarted)
                    End If
                    Me.dbResourceAllocator = New DbResourceAllocator(MyBase.Runtime, Me.configParameters, Me.unvalidatedConnectionString)
                End If
                Return Me.dbResourceAllocator.ConnectionString
            End Get
        End Property

        Public Property EnableRetries As Boolean
            Get
                Return Me._enableRetries
            End Get
            Set(ByVal value As Boolean)
                Me._enableRetries = value
                Me._ignoreCommonEnableRetries = True
            End Set
        End Property


        ' Fields
        Private _enableRetries As Boolean
        Private _ignoreCommonEnableRetries As Boolean
        Private configParameters As NameValueCollection
        Private dbResourceAllocator As DbResourceAllocator
        Private tableSyncObject As Object
        Private transactionConnectionTable As IDictionary([Of] Transaction, SharedConnectionInfo)
        Private unvalidatedConnectionString As String
    End Class
End Namespace

